package student.mindmap.core.model;

import com.google.gson.*;
import java.io.*;
import java.awt.*;
import java.util.*;
import java.util.List;
import javafx.scene.paint.Color;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import com.google.gson.stream.JsonReader;

public class MindMapPersistence {
    private static final Gson gson = new GsonBuilder()
            .registerTypeAdapter(Point.class, new PointAdapter())
            .registerTypeAdapter(Dimension.class, new DimensionAdapter())
            .registerTypeAdapter(Color.class, new ColorAdapter())
            .setPrettyPrinting()
            .create();

    // ================== 序列化结构 ==================
    private static class MindMapSchema {
        String rootId;
        List<NodeSchema> nodes;
    }

    private static class NodeSchema {
        String id;
        String text;
        String parentId;
        List<String> childrenIds;
        Point position;
        Dimension size;
    }

    // ================== 保存方法 ==================
    public static void saveToFile(MindMap map, String path) throws IOException {
        if (!path.toLowerCase().endsWith(".xmind")) {
            path += ".xmind";
        }
        MindMapSchema schema = convertToSchema(map);
        try (Writer writer = new FileWriter(path)) {
            gson.toJson(schema, writer);
        }
    }

    private static MindMapSchema convertToSchema(MindMap map) {
        MindMapSchema schema = new MindMapSchema();
        schema.rootId = map.getRoot().getId();

        schema.nodes = new ArrayList<>();
        for (MindMapNode node : map.getAllNodes()) {
            NodeSchema nodeSchema = new NodeSchema();
            nodeSchema.id = node.getId();
            nodeSchema.text = node.getText();
            nodeSchema.parentId = (node.getParent() != null) ? node.getParent().getId() : null;
            nodeSchema.childrenIds = getChildrenIds(node);
            nodeSchema.position = node.getPosition();
            nodeSchema.size = node.getSize();
            schema.nodes.add(nodeSchema);
        }
        return schema;
    }

    private static List<String> getChildrenIds(MindMapNode node) {
        List<String> ids = new ArrayList<>();
        for (MindMapNode child : node.getChildren()) {
            ids.add(child.getId());
        }
        return ids;
    }

    // ================== 加载方法 ==================
    public static MindMap loadFromFile(String path) throws IOException {
        if (!path.toLowerCase().endsWith(".xmind")) {
            throw new IllegalArgumentException("仅支持 .xmind 文件");
        }

        try (Reader reader = new FileReader(path)) {
            MindMapSchema schema = gson.fromJson(reader, MindMapSchema.class);
            return convertFromSchema(schema);
        }
    }

    private static MindMap convertFromSchema(MindMapSchema schema) {
        Map<String, MindMapNode> nodeRegistry = new HashMap<>();

        // 第一阶段：创建所有节点
        for (NodeSchema nodeSchema : schema.nodes) {
            MindMapNode node = new MindMapNode(nodeSchema.text);
            injectNodeData(node, nodeSchema);
            nodeRegistry.put(nodeSchema.id, node);
        }

        // 第二阶段：建立节点关系
        MindMap map = new MindMap();
        rebuildNodeRelationships(map, schema, nodeRegistry);

        return map;
    }

    private static void injectNodeData(MindMapNode node, NodeSchema schema) {
        // 通过反射设置ID（需要访问权限）
        try {
            java.lang.reflect.Field idField = MindMapNode.class.getDeclaredField("id");
            idField.setAccessible(true);
            idField.set(node, schema.id);
        } catch (Exception e) {
            throw new RuntimeException("Failed to set node ID", e);
        }

        node.setPosition(schema.position);
        node.setSize(schema.size);
    }

    private static void rebuildNodeRelationships(MindMap map, MindMapSchema schema,
                                                 Map<String, MindMapNode> registry) {
        // 重建父子关系
        for (NodeSchema nodeSchema : schema.nodes) {
            MindMapNode node = registry.get(nodeSchema.id);
            for (String childId : nodeSchema.childrenIds) {
                node.addChild(registry.get(childId));
            }
        }

        // 设置根节点并注册所有节点
        MindMapNode rootNode = registry.get(schema.rootId);
        map.setRoot(rootNode);
        registry.values().forEach(map::registerNode);
    }

    // ================== 自定义类型适配器 ==================
    private static class PointAdapter extends TypeAdapter<Point> {
        public void write(JsonWriter out, Point p) throws IOException {
            if (p == null) {
                out.nullValue(); // 允许写入null
                return;
            }
            out.beginObject()
                    .name("x").value(p.x)
                    .name("y").value(p.y)
                    .endObject();
        }

        public Point read(JsonReader in) throws IOException {
            int x = 0, y = 0;
            in.beginObject();
            while (in.hasNext()) {
                switch (in.nextName()) {
                    case "x": x = in.nextInt(); break;
                    case "y": y = in.nextInt(); break;
                }
            }
            in.endObject();
            return new Point(x, y);
        }
    }

    private static class DimensionAdapter extends TypeAdapter<Dimension> {
        public void write(JsonWriter out, Dimension d) throws IOException {
            out.beginObject()
                    .name("width").value(d.width)
                    .name("height").value(d.height)
                    .endObject();
        }

        public Dimension read(JsonReader in) throws IOException {
            int w = 0, h = 0;
            in.beginObject();
            while (in.hasNext()) {
                switch (in.nextName()) {
                    case "width": w = in.nextInt(); break;
                    case "height": h = in.nextInt(); break;
                }
            }
            in.endObject();
            return new Dimension(w, h);
        }
    }

    private static class ColorAdapter extends TypeAdapter<Color> {
        @Override
        public void write(JsonWriter out, Color value) throws IOException {
            if (value == null) {
                out.nullValue();
                return;
            }
            // 使用JavaFX Color的RGB值（0-255范围）
            out.value(String.format("#%06X",
                    (int)(value.getRed() * 255) << 16 |
                            (int)(value.getGreen() * 255) << 8 |
                            (int)(value.getBlue() * 255)
            ));
        }

        @Override
        public Color read(JsonReader in) throws IOException {
            if (in.peek() == JsonToken.NULL) {
                in.nextNull();
                return Color.web("#2196F3"); // 默认颜色
            }
            String hex = in.nextString();
            return Color.web(hex);
        }
    }
}